package com.stanwind.dbselector.aop;

import com.stanwind.dbselector.anno.DBNode;
import com.stanwind.dbselector.route.DefaultNodeRouter;
import com.sun.org.apache.xerces.internal.impl.xs.opti.DefaultNode;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PreDestroy;

import static com.stanwind.dbselector.DBSelectorConstant.HINT_CUSTOM_PLACE_HOLDER;

/**
 * NodesManager 准备hint
 *
 * @author : stan
 * @version : 1.0
 * @date :  2022/8/19 4:16 PM
 **/
@Aspect
@Order(-1)
@Component
@Slf4j
public class NodesManager {
    @Around(value = "@annotation(node)", argNames = "pjp, node")
    public Object around(ProceedingJoinPoint pjp, DBNode node) throws Throwable {

//        Class clazz = pjp.getTarget().getClass();
//        String methodName = pjp.getSignature().getName();
        //获取参数
//        Object[] args = pjp.getArgs();
//        MethodSignature ms = (MethodSignature) pjp.getSignature();
//        Method m = ms.getMethod();
        String sqlPrefix = convertHint(node);
        if (!StringUtils.isEmpty(sqlPrefix)) {
            log.debug("Hint sql: {}", sqlPrefix);
            NodeContext.getContext().putHint(sqlPrefix);
        }

        Object result = null;
        try {
            result = pjp.proceed();
        } finally {
            NodeContext.getContext().clear();
        }

        return result;
    }

    private String convertHint(DBNode node) throws Exception {
        switch (node.type()){
            case MASTER:
            case SLAVE:
                return wrapHint(node.type().getHint());
            case ASSIGN:
            case CUSTOM:
                return wrapHint(node);
            case IGNORE:
            default:
                return null;
        }
    }

    private String wrapHint(DBNode node) throws Exception {
        String hintTemplate = wrapHint(node.type().getHint());
        //使用node中的节点信息
        if (!StringUtils.isEmpty(node.node())) {
            return wrapHint(hintTemplate, node.node());
        }

        if (node.router() == DefaultNodeRouter.class) {
            throw new Exception("指定node节点未配置，且router配置不存在");
        }

        //router 计算结果node
        String nodeStr = node.router().newInstance().route();
        log.debug("当前route: {}", nodeStr);

        return wrapHint(hintTemplate, nodeStr);
    }

    private String wrapHint(String hintTemplate, String hint) {
        return hintTemplate.replace(HINT_CUSTOM_PLACE_HOLDER, hint);
    }

    private String wrapHint(String hintTemplate) {
        return "/*" + hintTemplate + "*/";
    }

    @PreDestroy
    public void destroy() {
        //shutdownHook
    }
}
